﻿/*========================== 
 * @author 郑金泉
 * @desc 方法请求AJAX桥
 * ========================= */
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web;
using System.Web.SessionState;
using System.Net;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Obsidian.Runtime;
using Obsidian.Utils;
using Obsidian.Web;
using Obsidian.Config;

namespace Obsidian.Action
{
    public class AjaxBridge : IHttpHandler, IRequiresSessionState
    {
        public void ProcessRequest(HttpContext context)
        {
            this.OnRequest(context);

            string appKey = this.GetAppKey();
            ApiConfig.ApiInfo apiInfo = ApiConfig.GetApiInfo(appKey);
            if (apiInfo.IsHttpRequest)
                this.ExecuteHttp(context);
            else
                this.ExecuteLocal(context);
        }

        private void ExecuteLocal(HttpContext context)
        {
            ApiConfig.ApiInfo api = ApiConfig.DefaultApiInfo;
            ActReqHandler arh = new ActReqHandler(context.Request.InputStream, api.AppKey);
            arh.Execute();
            context.Response.ContentType = "text/json";
            arh.OutputResponse(context.Response.OutputStream);
            context.Response.End();
        }

        private void ExecuteHttp(HttpContext context)
        {
            string appKey = this.GetAppKey();
            ApiConfig.ApiInfo apiInfo = ApiConfig.GetApiInfo(appKey);

            if (apiInfo == null)
            {
                this.ReturnErrorMsg("程序运行错误");
            }

            string timestamp = DateTimeUtil.ToUnixTimeStamp(DateTime.UtcNow);
            string strJson = ParamsReceiver.GetRequestInputStreamString();
            string sign = GenerateSign(apiInfo, timestamp, strJson);

            StringBuilder sb = new StringBuilder();
            sb.Append("#");
            sb.Append(apiInfo.AppKey).Append("|");
            sb.Append(timestamp).Append("|");
            sb.Append(this.GetSessionKey()).Append("|");
            sb.Append(sign).Append("$");
            sb.Append(strJson);

            BinaryReader reader = null;
            BinaryWriter writer = null;
            try
            {
                reader = new BinaryReader(HttpRequestor.PostStream(apiInfo.Url, sb.ToString()));
                writer = new BinaryWriter(context.Response.OutputStream);
                while (true)
                    writer.Write(reader.ReadByte());
            }
            catch (EndOfStreamException e) { }
            catch (WebException wex)
            {
                HttpWebResponse response = (HttpWebResponse)wex.Response;

                Stream stream = response.GetResponseStream();
                string responseText = IOUtil.StreamToString(stream);
                string code = Logger.Error(responseText);
                JObject jo = new JObject();
                jo["st"] = "ERROR";
                jo["msg"] = "发生程序错误:" + code;
                context.Response.Write(JsonConvert.SerializeObject(jo));
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                if (writer != null)
                    writer.Close();
            }
            context.Response.End();
        }

        private void ReturnErrorMsg(string msg)
        {
            JObject jo = new JObject();
            jo["st"] = "#ERROR#";
            jo["msg"] = msg;
            jo["dt"] = DateTimeUtil.NowString;
            string strJson = JsonConvert.SerializeObject(jo);
            HttpResponse response = HttpContext.Current.Response;
            response.Write(strJson);
            response.End();
        }

        private string GenerateSign(ApiConfig.ApiInfo apiInfo, string timestamp, string strJson)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(apiInfo.AppKey + "|");
            sb.Append(timestamp + "|");
            sb.Append(apiInfo.AppSecret + "|");
            sb.Append(strJson);
            string s = sb.ToString().ToLower();
            return StringUtil.Md5Encrypt(s);
        }

        private string ReqToString(JObject jo)
        {
            string act = Convert.ToString(((JValue)jo["act"]).Value);
            List<string> list = new List<string>();
            JObject o = (JObject)jo["prms"];
            if (o != null)
            {
                IEnumerable<JProperty> props = o.Properties();
                foreach (JProperty jp in props)
                    list.Add(jp.Name + "=" + Convert.ToString(((JValue)jp.Value).Value));
                list.Sort();
            }
            return "act=" + act + "&" + ArrayUtil.Join(list, "&");
        }


        protected virtual string GetAppKey()
        {
            return null;
        }

        protected virtual string GetSessionKey()
        {
            return "";
        }

        protected virtual void OnRequest(HttpContext context)
        {

        }

        protected virtual Assembly GetAssembly()
        {
            return null;
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}
